Skip to content

feat: add GitHub code repository provider (GitHub App auth)#5

Open
fedemaleh wants to merge 7 commits into
mainfrom
feature/github-code-provider
Open

feat: add GitHub code repository provider (GitHub App auth)#5
fedemaleh wants to merge 7 commits into
mainfrom
feature/github-code-provider

Conversation

@fedemaleh

Copy link
Copy Markdown
Collaborator

Summary

Adds a GitHub code repository provider (scripts/code-repo/github/), functionally equivalent to the JS github_provider.js it replaces. Selected with CODE_REPOSITORY_PROVIDER=github. Implements the code-repo interface-by-convention entirely in bash.

Auth: GitHub App (not PAT)

Chosen because it is org-owned (not tied to a person) and needs no manual rotation — an installation token is minted per run from the App's private key and expires on its own (~1h). build_context signs an RS256 JWT with openssl, exchanges it for an installation token (one curl), exports GH_TOKEN, and every other call uses the gh CLI (auto-installed via mise if absent).

Scripts

Script Behavior
build_context Validate env vars → ensure gh (mise) → RS256 JWT (openssl) → installation token → export GH_TOKEN
validate_repository_does_not_exist gh api /repos/... existence check vs create/import strategy
create_repository Generate-from-template: gh api POST /repos/{tpl}/generate (import → skip)
add_collaborators users → collaborators/{u}; teams → orgs/{org}/teams/{t}/repos/... (non-fatal per item)
create_secrets gh secret set (libsodium encryption handled by gh); fatal on failure (matches JS)
run_first_build Faithful port of enableContinuousIntegration: skip dynamic/, cancel in-progress + bounded wait, re-run in-progress/failed, tolerate "cannot be retried"

Config (env vars only)

GITHUB_APP_ID, GITHUB_PRIVATE_KEY (PEM), GITHUB_INSTALLATION_ID, GITHUB_ACCOUNT. GitHub.com only. Agent needs gh/openssl/curl; the App needs repo administration, contents, secrets, and actions permissions.

Also included

  • CI fix: the reusable shellcheck workflow runs find "$SCRIPT_DIRS" (quoted), so a space-separated entrypoint scripts was treated as one path and matched nothing. Split into one job per dir (shellcheck-entrypoint / shellcheck-scripts).
  • .gitignore: ignore .claude and .env.
  • README (GitHub provider section) + CHANGELOG.

Accepted deviation from the JS

run_first_build aborts on the first non-tolerated re-run error (exit 1) rather than aggregating all failures like the JS Promise.allSettled. Equivalent for success and abort-on-failure; multi-failure logging is not replicated (not reasonable in a sourced bash loop).

Test plan

  • Create path: set CODE_REPOSITORY_PROVIDER=github + the 4 App env vars; create an application with a GitHub template → repo generated private under GITHUB_ACCOUNT, NP_API_KEY secret set, collaborators added, CI triggered.
  • Import path: application importing an existing repo → creation skipped, secrets/CI still wired.
  • Secret failure is fatal: revoke the App's secrets permission → workflow fails loudly (no silent broken CI).
  • CI re-run: a template whose workflow starts before secrets exist → in-progress run cancelled and re-run after secrets are set.
  • ShellCheck CI green.

Notes

  • Workflow steps are sourced into a shared shell — hence return (skip) vs exit 1 (abort), and create_secrets/run_first_build use here-strings so exit 1 actually aborts.
  • Built via subagent-driven development: 5 tasks, per-task spec+quality review, and a whole-branch review; all scripts pass bash -n and ShellCheck severity=error locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant